// 请参考下面的代码，自己照着敲一遍

#include "VideoDecoder.h"
#include <QDebug>


extern "C"
{
    #include <libavcodec/avcodec.h>
    #include <libavformat/avformat.h>
    #include <libavutil/avutil.h>
    #include <libavutil/mathematics.h>
    #include <libavutil/hwcontext.h>      // 硬件上下文
    #include <libavutil/pixdesc.h>        // av_get_pix_fmt_name
}

#include <libavutil/hwcontext_d3d11va.h>


VideoDecoder::VideoDecoder()
    : m_formatContext(nullptr)
    , m_codecContext(nullptr)
    , m_videoStreamIndex(-1)
    , m_videoTimeBase{0, 0}
    , m_videoWidth(0)
    , m_videoHeight(0)
    , m_videoDurationMs(0)
    , m_fps(0)
    , m_isOpen(false)
    , m_error("")
    , m_hwDeviceCtx(nullptr)
    , m_hwPixelFormat(AV_PIX_FMT_NONE)
    , m_useHardwareDecoder(false)
    , m_decoderInfo("未初始化")
{
    avformat_network_init();
    qDebug() << "[VideoDecoder] 创建解码器";
}

VideoDecoder::~VideoDecoder()
{
    closeVideo();
    avformat_network_deinit();
    qDebug() << "[VideoDecoder] 销毁解码器";
}

bool VideoDecoder::openVideo(const QString& videoPath)
{
    QMutexLocker locker(&m_mutex);
    if(m_isOpen)
    {
        closeVideo();
    }

    //打开视频文件
    QByteArray pathBytes=videoPath.toUtf8();
    const char* filePath=pathBytes.constData();

    // 设置网络选项（用于网络视频）
    AVDictionary* opts = nullptr;
    av_dict_set(&opts, "timeout", "10000000", 0);       // 10秒超时（微秒）
    av_dict_set(&opts, "reconnect", "1", 0);            // 自动重连
    av_dict_set(&opts, "reconnect_streamed", "1", 0);   // 流媒体重连
    av_dict_set(&opts, "reconnect_delay_max", "5", 0);  // 最大重连延迟5秒

    int ret=avformat_open_input(&m_formatContext,filePath,nullptr,&opts);
    av_dict_free(&opts);  // 释放选项字典
    
    if(ret<0)
    {
        setError(QString("无法打开视频: %1").arg(filePath),ret);
        return false;
    }

    //读取流信息

    ret=avformat_find_stream_info(m_formatContext,nullptr);
    if(ret<0)
    {
        setError(QString("无法找到流信息: %1").arg(filePath),ret);
        return false;
    }

    //查找视频流
    m_videoStreamIndex=av_find_best_stream(m_formatContext,AVMEDIA_TYPE_VIDEO,-1,-1,nullptr,0);
    if(m_videoStreamIndex<0)
    {
        setError(QString("无法找到视频流: %1").arg(filePath));
        return false;
    }

    //获取视频流信息

    AVStream* videoStream=m_formatContext->streams[m_videoStreamIndex];
    if(!videoStream)
    {
        setError(QString("无法获取视频流: %1").arg(filePath));
        return false;
    }
    
    //计算视频时长
    if (m_formatContext->duration != AV_NOPTS_VALUE) {
        m_videoDurationMs = m_formatContext->duration / 1000;  // AV_TIME_BASE 微秒转毫秒
    } else {
        m_videoDurationMs = 0;
    }

    //查找解码器
    const AVCodec* codec = avcodec_find_decoder(videoStream->codecpar->codec_id);
    if(!codec)
    {
        setError(QString("无法找到解码器: %1").arg(filePath));
        return false;
    }
    

    //分配解码器上下文
    m_codecContext=avcodec_alloc_context3(codec);
    if(!m_codecContext)
    {
        setError(QString("无法分配解码器上下文: %1").arg(filePath));
        return false;
    }
    
    //复制参数
    ret=avcodec_parameters_to_context(m_codecContext,videoStream->codecpar);
    if(ret<0)
    {
        setError(QString("无法复制参数: %1").arg(filePath),ret);
        return false;
    }

    //尝试硬件解码

    bool hwSuccess=false;

    if (initHardwareDecoder(AV_HWDEVICE_TYPE_D3D11VA)) {
        m_codecContext->hw_device_ctx = av_buffer_ref(m_hwDeviceCtx);
        m_codecContext->get_format = getHardwareFormat;
        m_codecContext->opaque = this;  // 传递this指针给回调函数
        m_useHardwareDecoder = true;
        m_decoderInfo = "硬件-D3D11VA";
        hwSuccess = true;
        qDebug() << "[VideoDecoder] ✅ 使用 D3D11VA 硬件解码";
    }

    // 2. 如果 D3D11VA 失败，尝试 DXVA2（Windows 7+，兼容性更好）
if (!hwSuccess && initHardwareDecoder(AV_HWDEVICE_TYPE_DXVA2)) {
    m_codecContext->hw_device_ctx = av_buffer_ref(m_hwDeviceCtx);
    m_codecContext->get_format = getHardwareFormat;
    m_codecContext->opaque = this;
    m_useHardwareDecoder = true;
    m_decoderInfo = "硬件-DXVA2";
    hwSuccess = true;
    qDebug() << "[VideoDecoder] ✅ 使用 DXVA2 硬件解码";
}

// 3. 硬件解码失败，使用软件解码
if (!hwSuccess) {
    m_useHardwareDecoder = false;
    m_decoderInfo = "软件";
    qDebug() << "[VideoDecoder] ⚠️ 硬件解码不可用，使用软件解码";
}

    //打开解码器
    ret=avcodec_open2(m_codecContext,codec,nullptr);
    if(ret<0)
    {
        setError(QString("无法打开解码器: %1").arg(filePath),ret);
        return false;
    }



    //设置时间基
    m_videoTimeBase=videoStream->time_base;

    //保存视频信息
    m_videoWidth=m_codecContext->width;
    m_videoHeight=m_codecContext->height;

       // 计算帧率
       if (videoStream->avg_frame_rate.num > 0 && videoStream->avg_frame_rate.den > 0) {
        m_fps = av_q2d(videoStream->avg_frame_rate);
    } else if (videoStream->r_frame_rate.num > 0 && videoStream->r_frame_rate.den > 0) {
        m_fps = av_q2d(videoStream->r_frame_rate);
    }


    m_isOpen = true;
    qDebug() << "[VideoDecoder] 视频打开成功：" << filePath;
    qDebug() << "  分辨率：" << m_videoWidth << "x" << m_videoHeight;
    qDebug() << "  时长：" << m_videoDurationMs << "ms";
    qDebug() << "  帧率：" << m_fps << "fps";

    return true;


}


//关闭视频
void VideoDecoder::closeVideo()
{
    QMutexLocker locker(&m_mutex);
    if(!m_isOpen) return;

    freeResources();

    m_videoWidth = 0;
    m_videoHeight = 0;
    m_videoDurationMs = 0;
    m_fps = 0;
    m_isOpen = false;
    m_error = "";
    m_videoStreamIndex = -1;
    qDebug() << "[VideoDecoder] 视频关闭";
}

//解码一帧
VideoFrame VideoDecoder::decodeFrame(bool& isEof)
{
    QMutexLocker locker(&m_mutex);
    isEof = false;

    if(!m_isOpen) return VideoFrame();

    AVFrame* frame=av_frame_alloc();
    if(!frame)
    {
        setError(QString("无法分配AVFrame"));
        return VideoFrame();
    }

    AVPacket packet;
    av_init_packet(&packet);
    packet.data=nullptr;
    packet.size=0;

    bool hasFrame=false;
    int readRet;

    //读取数据包并且解码
    while((readRet=av_read_frame(m_formatContext,&packet))==0)
    {
        if(packet.stream_index==m_videoStreamIndex)
        {
            int ret=avcodec_send_packet(m_codecContext,&packet);
            if(ret<0)
            {
                setError(QString("无法发送数据包: %1").arg(packet.pts),ret);
                break;
            }

            //接收解码后的帧
            ret=avcodec_receive_frame(m_codecContext,frame);
            if(ret==0)
            {
                //解码成功
                hasFrame=true;

                // ========== 硬件解码：需要从GPU传输到CPU ==========
                if (m_useHardwareDecoder && frame->format == m_hwPixelFormat) {
                    // 创建软件帧（CPU内存）
                    AVFrame* sw_frame = av_frame_alloc();
                    
                    // 从GPU内存复制到CPU内存
                    int transfer_ret = av_hwframe_transfer_data(sw_frame, frame, 0);
                    
                    if (transfer_ret < 0) {
                        char errBuf[AV_ERROR_MAX_STRING_SIZE];
                        av_strerror(transfer_ret, errBuf, sizeof(errBuf));
                        qDebug() << "[VideoDecoder] 硬件帧传输失败：" << errBuf;
                        av_frame_free(&sw_frame);
                        av_frame_free(&frame);
                        av_packet_unref(&packet);
                        return VideoFrame();
                    }
                    
                    // 复制时间戳等元数据
                    sw_frame->pts = frame->pts;
                    
                    // 计算时间戳
                    int64_t ptsMs = 0;
                    if (sw_frame->pts != AV_NOPTS_VALUE) {
                        double sec = av_q2d(m_videoTimeBase) * sw_frame->pts;
                        ptsMs = static_cast<int64_t>(sec * 1000);
                    }
                    
                    // 释放硬件帧，返回软件帧
                    av_frame_free(&frame);
                    av_packet_unref(&packet);
                    
                    return VideoFrame(sw_frame, ptsMs);
                }
                
                // ========== 软件解码：直接返回 ==========
                //计算时间戳
                int64_t ptsMs=0;
                if(frame->pts!=AV_NOPTS_VALUE)
                {
                    double sec = av_q2d(m_videoTimeBase) * frame->pts;
                    ptsMs = static_cast<int64_t>(sec * 1000);
                }

                av_packet_unref(&packet);
                return VideoFrame(frame, ptsMs);

            } 
            else if(ret!=AVERROR(EAGAIN))
            {
                setError(QString("无法接收解码后的帧: %1").arg(packet.pts),ret);
                break;
            }
        }
        av_packet_unref(&packet);

    }
    // 处理文件结束
    if (readRet == AVERROR_EOF) {
        isEof = true;
        qDebug() << "[VideoDecoder] 到达文件末尾";
    } else if (readRet < 0) {
        setError("读取帧失败", readRet);
    }
    
    av_packet_unref(&packet);
    av_frame_free(&frame);
    
    return VideoFrame();  // 返回空帧
}


bool VideoDecoder::seek(int64_t positionMs)
{
    QMutexLocker locker(&m_mutex);

    if(!m_isOpen) return false;

    // 边界检查：不要 seek 到最后，留一点余量
    if(positionMs < 0) positionMs = 0;
    if(positionMs >= m_videoDurationMs - 1000) {  // 留1秒余量
        positionMs = m_videoDurationMs - 1000;
    }
    
    // 转换为流的 time_base 单位（正确的做法）
    int64_t seekPos = av_rescale_q(positionMs, AVRational{1, 1000}, m_videoTimeBase);

    // 清空解码器缓冲区
    if(m_codecContext)
    {
        avcodec_flush_buffers(m_codecContext);
    }

    // 执行跳转（使用流索引和流的时间基准）
    int ret = av_seek_frame(m_formatContext, m_videoStreamIndex, seekPos, AVSEEK_FLAG_BACKWARD);
    if(ret < 0)
    {
        setError(QString("跳转失败: %1").arg(positionMs), ret);
        return false;
    }

    qDebug() << "[VideoDecoder] 跳转到：" << positionMs << "ms (seekPos=" << seekPos << ")";
    return true;
}


int VideoDecoder::getVideoWidth() const
{
    return m_videoWidth;
}

int VideoDecoder::getVideoHeight() const
{
    return m_videoHeight;
}

int64_t VideoDecoder::getVideoDurationMs() const
{
    return m_videoDurationMs;
}

double VideoDecoder::getFps() const
{
    return m_fps;
}

bool VideoDecoder::isOpened() const
{
    QMutexLocker locker(&m_mutex);
    return m_isOpen;
}

QString VideoDecoder::getError() const
{
    return m_error;
}

void VideoDecoder::freeResources()
{
    if(m_codecContext)
    {
        avcodec_free_context(&m_codecContext);
        m_codecContext=nullptr;
    }
    if(m_formatContext)
    {
        avformat_close_input(&m_formatContext);
        m_formatContext=nullptr;
    }

    freeHardwareDecoder();
}

void VideoDecoder::setError(const QString& error,int ffmpegErrCode)
{
    m_error=error;
    if(ffmpegErrCode != -1)
    {
        char errStr[AV_ERROR_MAX_STRING_SIZE] = {0};
        av_strerror(ffmpegErrCode, errStr, sizeof(errStr));
        m_error += QString("（FFmpeg错误：%1）").arg(errStr);
    }
    qDebug() << "[VideoDecoder] 错误：" << m_error;
}




bool VideoDecoder::initHardwareDecoder(enum AVHWDeviceType type)
{
    //检查解码器是否支持该硬件类型
    const AVCodec* codec = avcodec_find_decoder(m_codecContext->codec_id);
    if (!codec) {
        qDebug() << "[VideoDecoder] 找不到解码器";
        return false;
    }

    for(int i=0;;i++)
    {
        const AVCodecHWConfig* config = avcodec_get_hw_config(codec, i);
        if (!config) {
            qDebug() << "[VideoDecoder] 解码器不支持" << av_hwdevice_get_type_name(type);
            return false;
        }
        
        // 3. 检查是否匹配目标硬件类型
        if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX &&
            config->device_type == type) {
            m_hwPixelFormat = config->pix_fmt;  // 保存硬件像素格式
            qDebug() << "[VideoDecoder] 找到硬件配置，像素格式：" << av_get_pix_fmt_name(m_hwPixelFormat);
            break;
        }
    }

 // 4. 创建硬件设备上下文
     int ret = av_hwdevice_ctx_create(
        &m_hwDeviceCtx,      // 输出：硬件设备上下文
        type,                // 硬件类型（D3D11VA、CUDA等）
        nullptr,             // 设备名称（nullptr表示自动选择）
        nullptr,             // 额外选项
        0                    // 标志位
     );

     if(ret<0)
     {
        char errBuf[AV_ERROR_MAX_STRING_SIZE];
        av_strerror(ret, errBuf, sizeof(errBuf));
        qDebug() << "[VideoDecoder] 创建硬件设备上下文失败：" << errBuf;
        return false;
     }

     qDebug() << "[VideoDecoder] 硬件设备上下文创建成功：" << av_hwdevice_get_type_name(type);
     return true;
}



void VideoDecoder::freeHardwareDecoder()
{
    if (m_hwDeviceCtx) {
        av_buffer_unref(&m_hwDeviceCtx);  // 释放硬件设备上下文
        m_hwDeviceCtx = nullptr;
        qDebug() << "[VideoDecoder] 释放硬件设备上下文";
    }
    
    m_hwPixelFormat = AV_PIX_FMT_NONE;
    m_useHardwareDecoder = false;
}

// ========== 硬件像素格式选择回调 ==========
enum AVPixelFormat VideoDecoder::getHardwareFormat(
    AVCodecContext* ctx, 
    const enum AVPixelFormat* pix_fmts)
{
    // 从用户数据中获取 VideoDecoder 实例
    VideoDecoder* decoder = static_cast<VideoDecoder*>(ctx->opaque);
    
    // 遍历FFmpeg提供的像素格式列表
    for (const enum AVPixelFormat* p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) {
        if (*p == decoder->m_hwPixelFormat) {
            qDebug() << "[VideoDecoder] 选择硬件像素格式：" << av_get_pix_fmt_name(*p);
            return *p;  // 返回硬件格式
        }
    }
    
    qDebug() << "[VideoDecoder] 未找到硬件像素格式，回退到软件解码";
    return AV_PIX_FMT_NONE;  // 找不到，回退到软件解码
}


// ========== 获取解码器信息 ==========
QString VideoDecoder::getDecoderInfo() const
{
    return m_decoderInfo;
}

// ========== 是否使用硬件解码 ==========
bool VideoDecoder::isUsingHardwareDecoder() const
{
    return m_useHardwareDecoder;
}
